home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / os2 / souper15.zip / NEWS.C < prev    next >
C/C++ Source or Header  |  1996-05-18  |  26KB  |  1,135 lines

  1. /* $Id: news.c 1.6 1996/05/18 21:06:26 cthuang Exp $
  2.  *
  3.  * Get news from NNTP server.
  4.  */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <time.h>
  9. #include "socket.h"
  10. #include "nntp.h"
  11. #include "nntpcl.h"
  12. #include "souper.h"
  13.  
  14. /* article number range in the .newsrc file */
  15. typedef struct aRange {
  16.     struct aRange *next;    /* pointer to next */
  17.     ArticleNumber lo, hi;    /* article number range */
  18. } Range;
  19.  
  20. /* newsgroup entry in the .newsrc file */
  21. typedef struct aNewsrcGroup {
  22.     struct aNewsrcGroup *next;    /* pointer to next */
  23.     char *name;            /* newsgroup name */
  24.     Range *readList;        /* list of read article ranges */
  25.     char subscribed;        /* subscribed flag */
  26. } NewsrcGroup;
  27.  
  28. static NewsrcGroup *nrcList;    /* list of .newsrc entries. */
  29. static long byteCount;        /* current size of fetched news */
  30. static char killEnabled;    /* kill processing enabled for this group */
  31. static FILE *tmpF;        /* temporary file for article */
  32. static int groupCnt;        /* current group number */
  33.  
  34. #ifdef __WIN32__
  35. #include <conio.h>
  36. #endif
  37.  
  38. /* Read the article numbers from a .newsrc line. */
  39.  
  40. static Range *
  41. getReadList (FILE *nrcFile)
  42. {
  43.     static const char digits[] = "%[0123456789]";
  44.     Range *pLast, *rp, *head;
  45.     ArticleNumber lo, hi;
  46.     int c;
  47.     char *range;
  48.     char buf[20];
  49.  
  50.     /* Initialize subscription list */
  51.     pLast = NULL;
  52.     head = NULL;
  53.  
  54.     /* Expect [ \n] */
  55.     c = fgetc(nrcFile);
  56.  
  57.     while (c != '\n' && c != EOF) {
  58.     /* Expect number */
  59.     if (fscanf(nrcFile, digits, buf) != 1)
  60.         break;
  61.     lo = atol(buf);
  62.  
  63.     /* Get space for new list entry */
  64.     rp = (Range *)xmalloc(sizeof(Range));
  65.  
  66.     /* Expect [-,\n] */
  67.     c = fgetc(nrcFile);
  68.     if (c == '-') {
  69.         /* Is a range */
  70.         /* Expect number */
  71.         if (fscanf(nrcFile, digits, buf) != 1)
  72.         break;
  73.         hi = atol(buf);
  74.  
  75.         rp->lo = lo;
  76.         rp->hi = hi;
  77.  
  78.         if (lo != 1 || hi != 0) {
  79.         /* Reverse them in case they're backwards */
  80.         if (hi < lo) {
  81.             rp->lo = hi;
  82.             rp->hi = lo;
  83.         }
  84.         }
  85.  
  86.         /* Expect [,\n] */
  87.         c = fgetc(nrcFile);
  88.     } else {
  89.         /* Not a range */
  90.         rp->lo = rp->hi = lo;
  91.     }
  92.  
  93.     /* Check if range overlaps last one */
  94.     if (pLast != NULL && rp->lo <= pLast->hi + 1) {
  95.         /* Combine ranges */
  96.         if (rp->lo < pLast->lo) pLast->lo = rp->lo;
  97.         if (rp->hi > pLast->hi) pLast->hi = rp->hi;
  98.  
  99.         /* Free old one */
  100.         free(rp);
  101.     } else {
  102.         /* No overlap, update pointers */
  103.         if (pLast == NULL) {
  104.         head = rp;
  105.         } else {
  106.         pLast->next = rp;
  107.         }
  108.         rp->next = NULL;
  109.         pLast = rp;
  110.     }
  111.     }
  112.  
  113.     while (c != '\n' && c != EOF)
  114.     c = fgetc(nrcFile);
  115.  
  116.     return head;
  117. }
  118.  
  119. /* Read the .newsrc file and point nrcList to list of newsgroups entries.
  120.  * Return TRUE if successful.
  121.  */
  122. static int
  123. readNewsrc (void)
  124. {
  125.     FILE *nrcFile;
  126.     char group_name[BUFSIZ], ch;
  127.     NewsrcGroup *head, *np, *lnp;
  128.  
  129.     /* lnp points to last entry */
  130.     lnp = NULL;
  131.     head = NULL;
  132.  
  133.     /* Open it */
  134.     if ((nrcFile = fopen(newsrcFile, "r")) == NULL) {
  135.     fprintf(stderr, "%s: can't open %s\n", progname, newsrcFile);
  136.     return 0;
  137.     }
  138.  
  139.     /* Read newsgroup entry */
  140.     while (fscanf(nrcFile, "%[^:! \t\n]", group_name) == 1) {
  141.     if (group_name[0] == '\0')
  142.         break;
  143.  
  144.     /* Allocate a new entry */
  145.     np = (NewsrcGroup *)xmalloc(sizeof(NewsrcGroup));
  146.     ch = fgetc(nrcFile);
  147.     if (ch == '\n') {
  148.         /* The user didn't end the line with a colon. */
  149.         np->subscribed = 1;
  150.         np->readList = NULL;
  151.     } else {
  152.         /* Parse subscription list */
  153.         np->subscribed = (ch == ':');
  154.         np->readList = getReadList(nrcFile);
  155.     }
  156.     np->name = xstrdup(group_name);
  157.     np->next = NULL;
  158.  
  159.     /* Add to list */
  160.     if (lnp == NULL) {
  161.         head = np;
  162.     } else {
  163.         lnp->next = np;
  164.     }
  165.     lnp = np;
  166.     }
  167.  
  168.     fclose(nrcFile);
  169.     nrcList = head;
  170.     return 1;
  171. }
  172.  
  173. /* Write the article numbers for a .newsrc entry. */
  174.  
  175. static void
  176. putReadList (FILE *fd, Range *head)
  177. {
  178.     while (head != NULL) {
  179.     if (head->lo == head->hi)
  180.         fprintf(fd, "%ld", head->lo);
  181.     else
  182.         fprintf(fd, "%ld-%ld", head->lo, head->hi);
  183.     head = head->next;
  184.     if (head != NULL) fputc(',', fd);
  185.     }
  186.     fputc('\n', fd);
  187. }
  188.  
  189. /* Rewrite the updated .newsrc file. */
  190.  
  191. int
  192. writeNewsrc (void)
  193. {
  194.     char oldFile[FILENAME_MAX];
  195.     FILE *nrcFile;
  196.     NewsrcGroup *np;
  197.  
  198.     if (readOnly || !doNews || !nrcList) return 0;
  199.  
  200.     /* Back up old .newsrc file. */
  201.     sprintf(oldFile, "%s.old", newsrcFile);
  202.     remove(oldFile);
  203.     rename(newsrcFile, oldFile);
  204.  
  205.     if ((nrcFile = fopen(newsrcFile, "w")) == NULL) {
  206.     fprintf(stderr, "%s: can't write %s\n", progname, newsrcFile);
  207.     return 0;
  208.     }
  209.  
  210.     for (np = nrcList; np != NULL; np = np->next) {
  211.     fputs(np->name, nrcFile);
  212.     fputc(np->subscribed ? ':' : '!', nrcFile);
  213.     fputc(' ', nrcFile);
  214.     putReadList(nrcFile, np->readList);
  215.     }
  216.  
  217.     fclose(nrcFile);
  218.     return 1;
  219. }
  220.  
  221. /* Get first unread article number. */
  222.  
  223. static ArticleNumber
  224. firstUnread (Range *head, ArticleNumber lo)
  225. {
  226.     if (head == NULL)
  227.     return lo;
  228.     return head->hi + 1;
  229. }
  230.  
  231. /* Determine if the article number has been read */
  232.  
  233. static int
  234. isRead (ArticleNumber num, Range *head)
  235. {
  236.     /* Look through the list */
  237.     while (head != NULL) {
  238.     if (num < head->lo) return 0;
  239.     if (num >= head->lo && num <= head->hi) return 1;
  240.     head = head->next;
  241.     }
  242.     return 0;
  243. }
  244.  
  245. /* Mark article as read. */
  246.  
  247. static Range *
  248. markRead (ArticleNumber num, Range *head)
  249. {
  250.     Range *rp, *trp, *lrp;
  251.  
  252.     rp = head;
  253.  
  254.     /* If num is much lower than lowest range, or the list is
  255.        empty, we need new entry */
  256.     if (rp == NULL || num < rp->lo - 1) {
  257.     trp = (Range *)xmalloc(sizeof(Range));
  258.     trp->lo = trp->hi = num;
  259.     trp->next = rp;
  260.     return trp;
  261.     }
  262.  
  263.     /* lrp remembers last entry in case we need to add a new entry */
  264.     lrp = NULL;
  265.  
  266.     /* Find appropriate entry for this number */
  267.     while (rp != NULL) {
  268.     /* Have to squeeze one in before this one? */
  269.     if (num < rp->lo - 1) {
  270.         trp = (Range *)xmalloc(sizeof(Range));
  271.         trp->lo = trp->hi = num;
  272.         trp->next = rp;
  273.         lrp->next = trp;
  274.         return head;
  275.     }
  276.  
  277.     /* One less than entry's lo? */
  278.     if (num == rp->lo - 1) {
  279.         rp->lo = num;
  280.         return head;
  281.     }
  282.  
  283.     /* In middle of range, do nothing */
  284.     if (num >= rp->lo && num <= rp->hi) return head;
  285.  
  286.     /* One too high, must check if we merge with next entry */
  287.     if (num == rp->hi + 1) {
  288.         if (rp->next != NULL && num == rp->next->lo - 1) {
  289.         trp = rp->next;
  290.         rp->hi = trp->hi;
  291.         rp->next = trp->next;
  292.         free(trp);
  293.         return head;
  294.         } else {
  295.         /* No merge */
  296.         rp->hi = num;
  297.         return head;
  298.         }
  299.     }
  300.  
  301.     lrp = rp;
  302.     rp = rp->next;
  303.     }
  304.  
  305.     /* We flew off the end and need a new entry */
  306.     trp = (Range *)xmalloc(sizeof(Range));
  307.     trp->lo = trp->hi = num;
  308.     trp->next = NULL;
  309.     lrp->next = trp;
  310.  
  311.     return head;
  312. }
  313.  
  314. /* Sanity fixes to the read article number list */
  315.  
  316. static Range *
  317. fixReadList (NewsrcGroup *np, ArticleNumber lo, ArticleNumber hi)
  318. {
  319.     Range *head, *rp1, *rp2, *rp3;
  320.  
  321.     head = np->readList;
  322.     if (head != NULL) {
  323.     /* Go to last entry in list. */
  324.     for (rp1 = head; rp1->next != NULL; rp1 = rp1->next)
  325.         ;
  326.     if (rp1->hi > hi) {
  327.         /* The highest read article number is greater than the highest
  328.          * available article number.
  329.          */
  330. #if 0
  331.         printf("%s: Somebody reset %s -- assuming nothing read.\n",
  332.         progname, np->name);
  333. #endif
  334.  
  335.         /* Mark everything as read. */
  336.         head->lo = 1;
  337.         head->hi = hi;
  338.  
  339.         /* Free the rest */
  340.         rp2 = head->next;
  341.         while (rp2 != NULL) {
  342.         rp3 = rp2->next;
  343.         free(rp2);
  344.         rp2 = rp3;
  345.         }
  346.  
  347. #if 0
  348.         /* If lowest available article is 1, then leave read list empty,
  349.          * otherwise when group is reset, the first article would be
  350.          * skipped.
  351.          */
  352.         if (lo <= 1) {
  353.         free(head);
  354.         return NULL;
  355.         }
  356. #endif
  357.         head->next = NULL;
  358.         return head;
  359.     }
  360.  
  361.     /* Walk through the list and eliminate ranges lower than the lowest
  362.      * available article
  363.      */
  364.     rp1 = he